/*
 * Copyright (c) 2010 Curtis Boyden.  All rights reserved. 
 * This software was developed by Curtis Boyden and is provided under the terms 
 * of the GNU Lesser General Public License, Version 2.1. You may not use 
 * this file except in compliance with the license. If you need a copy of the license, 
 * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is ejMud
 * (Ewerp Java MUD).  The Initial Developer is Curtis Boyden.
 *
 * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
 * the license for the specific language governing your rights and limitations.
 */

package com.ewerp.mud.commands.engine;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;

import com.ewerp.mud.commands.ICommand;
import com.ewerp.mud.commands.ICommandEngine;
import com.ewerp.mud.core.exceptions.FailedToPushCommandException;
import com.ewerp.mud.core.lifecycle.ILifecycleListener;
import com.ewerp.mud.core.plugin.AbstractPlugin;
import com.ewerp.mud.core.plugin.IPlugin;

/**
 * The default implementation of the command engine uses a
 * {@link LinkedBlockingQueue} to store commands until the execution thread gets
 * a change to process the commands. There is no waiting between commands, they
 * are processed as quickly as possible.
 * 
 * @author cboyden
 * 
 */
public class EwerpCommandEngine extends AbstractPlugin implements ICommandEngine, ILifecycleListener, Runnable {
    private static final EwerpCommandEngine instance = new EwerpCommandEngine();
    
    protected LinkedBlockingQueue<ICommand> commandQueue = new LinkedBlockingQueue<ICommand>();

    public static final EwerpCommandEngine getInstance() {
        return instance;
    }
    
    protected EwerpCommandEngine() {
    }
    
    @Override
    public void pushCommand(ICommand command) throws IllegalArgumentException, FailedToPushCommandException {
        if (command == null) {
            throw new IllegalArgumentException("Parameter [command] MAY NOT be null");
        }

        try {
            commandQueue.put(command);
        } catch (Exception e) {
            throw new FailedToPushCommandException("Unable to push command onto the stack", e);
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                ICommand cmd = commandQueue.take();
                if (cmd instanceof IPlugin) {
                    ((IPlugin) cmd).registerPluginManager(getPluginManager());
                }
                cmd.execute();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    @Override
    public List<Class<?>> getInterfaces() {
        return Arrays.asList(new Class<?>[] {ICommandEngine.class});
    }

    @Override
    public void init() {
        // Nothing to do here
    }

    @Override
    public void start() {
        (new Thread(this)).start();
    }

    @Override
    public void stop() {
        // Nothing to do here
    }

}
